package main

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"log"
	"strconv"
	"time"
	"os"
	"io"
)

func Connect(accessKeyId, accessSecretKey string, port uint16) *s3.S3 {
	cred := credentials.NewStaticCredentials(accessKeyId, accessSecretKey, "")
	conf := aws.Config{
		Region:      aws.String("us-east-1"),
		Endpoint:    aws.String("s3.amazonaws.com:" + strconv.Itoa(int(port))),
		Credentials: cred,
		DisableSSL:  aws.Bool(true)}

	sess := session.Must(session.NewSession(&conf))
	return s3.New(sess)
}

func Timing(f func()) {
	start := time.Now()
	f()
	log.Printf("last operation cost: %v\n", time.Now().Sub(start))
}

const (
	AccessKeyId = "44CF9590006BF252F707"
	AccessSecretKey = "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
	Port = 8080
)

func main() {
	srv := Connect(AccessKeyId, AccessSecretKey, Port)
	if srv == nil {
		log.Fatalln("connect to server failed")
		return
	}

	_, err := srv.CreateBucket(&s3.CreateBucketInput{Bucket: aws.String("foo")})
	if err != nil {
		log.Fatalln(err)
	}

	Timing(func() {
		f, err := os.Open("hello.txt")
		if err != nil {
			log.Fatalln(err)
		}

		output, err := srv.PutObject(&s3.PutObjectInput{
			Bucket: aws.String("foo"),
			Key: aws.String("index.html"),
			Body: f,
			ServerSideEncryption: aws.String("AES256")})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(output)

		f.Close()
	})

	Timing(func() {
		f, err := os.Open("hello.txt")
		if err != nil {
			log.Fatalln(err)
		}

		output, err := srv.PutObjectAcl(&s3.PutObjectAclInput{
			Bucket: aws.String("foo"),
			Key: aws.String("index.html"),
			ACL: aws.String("public-read-write")})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(output)

		f.Close()
	})

	Timing(func() {
		f, err := os.Open("hello.txt")
		if err != nil {
			log.Fatalln(err)
		}

		output, err := srv.PutObject(&s3.PutObjectInput{
			Bucket: aws.String("foo"),
			Key: aws.String("dir/index.html"),
			Body: f})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(output)

		f.Close()
	})

	_, err = srv.PutBucketWebsite(&s3.PutBucketWebsiteInput{
		Bucket: aws.String("foo"),
		WebsiteConfiguration: &s3.WebsiteConfiguration{
			IndexDocument: &s3.IndexDocument{Suffix: aws.String("index.html")},
			ErrorDocument: &s3.ErrorDocument{Key: aws.String("index.html")}}})
	if err != nil {
		log.Fatalln(err)
	}

	out, err := srv.GetBucketWebsite(&s3.GetBucketWebsiteInput{
		Bucket: aws.String("foo"),
	})
	if err != nil {
		log.Fatalln(err)
	}
	log.Println(out)

	Timing(func() {
		f, err := os.Open("bigger.tar.gz")
		if err != nil {
			log.Fatalln(err)
		}

		output, err := srv.PutObject(&s3.PutObjectInput{
			Bucket: aws.String("foo"),
			Key: aws.String("bar_encrypt"),
			Body: f,
			ServerSideEncryption: aws.String("AES256")})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(output)

		f.Close()
	})

	Timing(func() {
		output, err := srv.CopyObject(&s3.CopyObjectInput{
			Bucket: aws.String("foo"),
			Key: aws.String("bar_decrypt"),
			CopySource: aws.String("foo/bar_encrypt"), MetadataDirective: aws.String("copy")})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(output)
	})

	Timing(func() {
		output, err := srv.GetObject(&s3.GetObjectInput{
			Bucket: aws.String("foo"),
			Key: aws.String("bar_decrypt")})

		if err != nil {
			log.Fatalln(err)
		}

		f, err := os.Create("bigger.tar.gz.2")
		if err != nil {
			log.Fatalln(err)
		}

		_, err = io.Copy(f, output.Body)
		if err != nil {
			log.Fatalln(err)
		}

		f.Close()
	})


	Timing(func() {
		output, err := srv.CreateMultipartUpload(&s3.CreateMultipartUploadInput{
			Bucket: aws.String("foo"),
			Key: aws.String("multipart")})
		if err != nil {
			log.Fatalln(err)
		}
		log.Println(output)

		uploadList := s3.CompletedMultipartUpload{}

		for i := 1; i <= 10; i++ {
			f, err := os.Open("/etc/hosts")
			if err != nil {
				log.Fatalln(err)
			}

			partOutput, err := srv.UploadPart(&s3.UploadPartInput{
				Body:          f,
				Bucket:        aws.String("foo"),
				Key:           aws.String("multipart"),
				PartNumber:    aws.Int64(int64(i)),
				UploadId:      output.UploadId})
			if err != nil {
				log.Fatalln(err)
			}

			uploadList.Parts = append(uploadList.Parts, &s3.CompletedPart{
				ETag: partOutput.ETag,
				PartNumber: aws.Int64(int64(i))})

			log.Println(partOutput)
			f.Close()
		}

		completeOutput, err := srv.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
			Bucket:          aws.String("foo"),
			Key:             aws.String("multipart"),
			UploadId:        output.UploadId,
			MultipartUpload: &uploadList})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(completeOutput)
	})

	Timing(func() {
		output, err := srv.GetObject(&s3.GetObjectInput{
			Bucket: aws.String("foo"),
			Key: aws.String("multipart")})

		if err != nil {
			log.Fatalln(err)
		}

		f, err := os.Create("multipart")
		if err != nil {
			log.Fatalln(err)
		}

		_, err = io.Copy(f, output.Body)
		if err != nil {
			log.Fatalln(err)
		}

		f.Close()
	})

	Timing(func() {
		output, err := srv.ListObjects(&s3.ListObjectsInput{
			Bucket: aws.String("foo")})

		if err != nil {
			log.Fatalln(err)
		}

		log.Println(output)
	})
}
